/**************************************************************************************
*
*	Copyright (C) 2009 - 2012 Brent Andrew O. Chua - See LICENSE.txt for more info.
*		
*	Filename	-	RenderEntryModel.cpp
*
*	Comments	-	See RenderEntryModel.h
*
**************************************************************************************/
#include "../Include/RenderEntryModel.h"
#include "../Include/GraphicsPipeline.h"
#include "../Include/Engine.h"
#include "../Include/GlobalGraphicsStrings.h"

namespace Pulse
{
	RenderEntryModel::RenderEntryModel( void )
		: m_pGeoRenderInfo( PSX_NULL ), m_pIndexBuffer( PSX_NULL ), 
		m_pGeoSubset( PSX_NULL ), m_pRenderPass( PSX_NULL )
	{
		SetStage( ERenderViewStage::UNKNOWN );

		ParameterSystem *pParamSys = Engine::GetInstance()->GetRenderer()->GetParameterSystem();

		pParamWorld = pParamSys->GetMatrix( GFX_PARAM_TRANSFORM_WORLD );
		pParamView = pParamSys->GetMatrix( GFX_PARAM_CAM_VIEW );
		pParamProjection = pParamSys->GetMatrix( GFX_PARAM_PROJECTION );
		pParamWorldView = pParamSys->GetMatrix( GFX_PARAM_WORLD_VIEW );
		pParamWorldViewProj = pParamSys->GetMatrix( GFX_PARAM_WORLD_VIEW_PROJ );
	
		PSX_Assert( pParamWorld, "Parameter pParamWorld shouldn't be null." );
		PSX_Assert( pParamView, "Parameter pParamView shouldn't be null." );
		PSX_Assert( pParamProjection, "Parameter pParamProjection shouldn't be null." );
		PSX_Assert( pParamWorldView, "Parameter pParamWorldView shouldn't be null." );
		PSX_Assert( pParamWorldViewProj, "Parameter pParamWorldViewProj shouldn't be null." );
	}

	RenderEntryModel::~RenderEntryModel( void )
	{

	}

	void RenderEntryModel::SetWorldTransformRef( const Matrix4x4 *pWorld )
	{

	}

	void RenderEntryModel::PreExecute( GraphicsPipeline *pPipeline )
	{
		//pPipeline->IAClearStates();
	}

	void RenderEntryModel::Execute( GraphicsPipeline *pPipeline )
	{
		if ( pParamWorld->GetMatrix() == PSX_NULL )
		{
			PSX_PushWarning( "World transform is not set." );
			return;
		}

		pPipeline->ClearStageStates( TRUE, TRUE, TRUE, FALSE, FALSE, FALSE );

		// bind parameters
		for ( SIZE_T i = 0; i < m_params.GetSize(); ++i )
		{
			m_params[i]->BindParameters();
		}

		pPipeline->IASetTopology( m_topology );
		pPipeline->IASetInputLayout( m_pGeoRenderInfo->m_pInputLayout );
		
		const SIZE_T numVB = m_pGeoRenderInfo->m_vertexBuffers.GetSize();

		for ( SIZE_T i = 0; i < numVB; ++i )
		{
			pPipeline->IASetVertexBuffer( (UINT)i, m_pGeoRenderInfo->m_vertexBuffers[i], m_pGeoSubset->m_indicesOffset );
		}

		pPipeline->IASetIndexBuffer( m_pIndexBuffer );

		// Set World-View and World-View-Proj matrix
		const Matrix4x4 *pWorld = pParamWorld->GetMatrix();
		const Matrix4x4 *pView = pParamView->GetMatrix();
		const Matrix4x4 *pProj = pParamProjection->GetMatrix();

		Matrix4x4 worldView = *pWorld * *pView;
		Matrix4x4 worldViewProj = worldView * *pProj;
		
		pParamWorldView->SetMatrix( &worldView );
		pParamWorldViewProj->SetMatrix( &worldViewProj );
		
		m_pRenderPass->ConfigurePipeline( pPipeline );
	
		pPipeline->ApplyStageStates( TRUE, TRUE, TRUE, FALSE, FALSE, FALSE );

		// TODO: Figure out if we have index buffer or create a new render entry
		//	just for rendering non-indexed geometries.
		pPipeline->DrawIndexed( m_pIndexBuffer->GetDescription()->numIndices );
	}

	void RenderEntryModel::PostExecute( GraphicsPipeline *pPipeline )
	{
		// 
	}
}